"""
    Partner Gate applicatoin.
    Handles requests for md5 urls and
    total calls for internal use.
"""

import datetime
import time
from converters import md5Converter
from flask import Flask, g, request
from tornado.database import Connection

# configuration, default
DEBUG = False
DB_HOST = "localhost"
DB_NAME = "PartnerGate_db"
DB_USER = "root"
DB_PASSWD = "root"
TRACE_FILE = "app_log"


def create_app(config=None):
    """Factory function to create the pgate flask application."""
    app = Flask(__name__)

    # setup the config
    if not config:
        config = __name__
    app.config.from_object(config)
    app.config.from_envvar("PGATE_SETTINGS", silent=True)

    app.url_map.converters['md5'] = md5Converter.md5Converter

    # add file logging handler
    import logging
    from logging.handlers import TimedRotatingFileHandler
    file_handler = TimedRotatingFileHandler(app.config['TRACE_FILE'],
                                            'midnight', 1)
    #file_handler.setLevel(logging.INFO)
    app.logger.addHandler(file_handler)

    def gated(expires, max_age, content_type="text/javascript"):
        """decorator for a partner gate response"""
        def decorator(func):
            """decorator function for a standard response from pgate"""
            from functools import update_wrapper

            def gate_request(*args, **kwargs):
                """Set the appropriate headers"""
                resp = app.make_response(f(*args, **kwargs))
                resp.headers['Content-type'] = content_type
                resp.headers['Expires'] = expires
                resp.headers['Cache-Control'] = 'max-age=%s' % str(max_age)
                return resp

            return update_wrapper(gate_request, func)
        return decorator

    # NOTE: If a rule ends with a slash and is requested without a slash,
    # the user is automatically redirected to the
    # same page with a trailing slash attached.
    @app.route("/total/<int:partner_id>/", methods=['GET'])
    @gated(expires="+1h", max_age=3600)
    def total(partner_id):
        """Returns the total number of urls present for a given partner_id.

           Examples:
               http://buzzfeed/total/50005/ => 2, 200 OK"""
        
        return str(get_totals(partner_id))

    @app.route("/<int:partner_id>/<md5:url>",
               methods=['GET'], strict_slashes=False)
    @gated(expires="+7d", max_age=604800)
    def access(partner_id, url):
        """Returns the date the url was first seen.
           If a queryparameter named 'callback' exists, will wrap
           the response in a function with query string value.

           http://buzzfeed/50005/e018e2d49783e212c38c33f69fed6c01?callback=a
             => a(1313523773), 200 OK
           http://buzzfeed/50005/e018e2d49783e212c38c33f69fed6c01
             => 1313523773, 200 OK
           http://buzzfeed/50005/e018e2d49783e212c38c33f69fed6c01/
             => 1313523773, 200 OK"""
        first_occur = 0
        first_occur = get_url(partner_id, url)
        if not (first_occur > 0):
           first_occur = insert_url(partner_id,url)	
           

        resp = str(first_occur)
        callback = request.args.get("callback")
        if callback:
            resp = "%s(%s);\n" % (callback, resp)

        return resp

    @app.errorhandler(404)
    def page_not_found(error):
        """Returns the default value "0", 200 OK when a url would normally
           come back as a HTTP 404 error

           Examples:
               http://pglb.buzzfed.com/-0005/bogus-looking-url => 0, 200 OK
        """
        app.logger.error(error)
        return "0", 200

    @app.errorhandler(500)
    def default_error_handler(error):
        """Returns the default value "0", 200 OK when a url would normally
           come back as a HTTP 500 error. """
        app.logger.error(error)
        return "0", 200

    @app.before_request
    def before_request():
        """Make sure we are connected to the database each request."""
        g.db = connect_db()

    def connect_db():
        """Returns a new connection to the database."""
        return Connection(app.config['DB_HOST'], app.config['DB_NAME'],
                          app.config['DB_USER'], app.config['DB_PASSWD'])
    
    
   """ Database accessors """ 
   def get_url(partner_id, url):
        dbresp = g.db.get("Select first_occurrence from partner_gate_lookup where partner_id = %s and tracking_url = CAST(UNHEX(%s) AS BINARY(16)) order by first_occurrence desc LIMIT 1;", partner_id, url)
        return dbresp.first_occurrance
    
    def insert_url(partner_id,url): 
       g.db.execute('Insert into partner_gate_lookup (partner_id,tracking_url,first_occurrence,lookup_status) Values (%s,UNHEX(%s),UNIX_TIMESTAMP(),1);', partner_id, url)       
       return int(time.time())

    def get_totals(partner_id):
        total = g.db.get("select count(*) as count from" \
                         " PartnerGate_db.PartnerGateLookup" \
                         " where partnerid=%s;", partner_id)
        
 	return total['count']

    @app.after_request
    def after_request(response):
        """Closes the database at the end of the request."""
        close_connection()
        return response

    def close_connection():
        """Close the database connection if it was set."""
        if hasattr(g, 'db'):
            g.db.close()

    return app
